﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using com.google.zxing.qrcode;
using System.Windows.Threading;
using System.Collections.ObjectModel;
using Microsoft.Devices;
using System.Windows.Navigation;
using com.google.zxing.common;
using com.google.zxing;
using CivilleWP7.Civille.Source;
using System.Data.Services.Client;
using CivilleWP7.CivilleDataServiceReference;

namespace CivilleWP7.Views.Pages
{
    public partial class VerifyTask : PhoneApplicationPage
    {

        private readonly DispatcherTimer _timer;
        private readonly ObservableCollection<string> _matches;

        private PhotoCameraLuminanceSource _luminance;
        private QRCodeReader _reader;
        private PhotoCamera _photoCamera;
        private int taskID;
        private TaskHistory currentTaskHistory;
        private int rewardID = -1;
        private bool levelChanged = false;

        public VerifyTask()
        {
            InitializeComponent();

            _matches = new ObservableCollection<string>();
            _matchesList.ItemsSource = _matches;

            _timer = new DispatcherTimer();
            _timer.Interval = TimeSpan.FromMilliseconds(250);
            _timer.Tick += new EventHandler(_timer_Tick);
        }

        void _timer_Tick(object sender, EventArgs e)
        {
            try
            {
                _photoCamera.GetPreviewBufferY(_luminance.PreviewBufferY);
                var binarizer = new HybridBinarizer(_luminance);
                var binBitmap = new BinaryBitmap(binarizer);
                var result = _reader.decode(binBitmap);
                Dispatcher.BeginInvoke(() => { DisplayResult(result.Text); });
            }
            catch
            {
            }
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            _photoCamera = new PhotoCamera();
            _photoCamera.Initialized += OnPhotoCameraInitialized;
            _previewVideo.SetSource(_photoCamera);

            CameraButtons.ShutterKeyHalfPressed += (o, arg) => _photoCamera.Focus();

            base.OnNavigatedTo(e);

            int selectedItemId = 0;
            try
            {
                selectedItemId = Int32.Parse(NavigationContext.QueryString["id"]);
            }
            catch (Exception ex)
            {
                selectedItemId = 0;
            }
            taskID = selectedItemId;
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            _photoCamera.Dispose();
            _timer.Tick -= new EventHandler(_timer_Tick);
            base.OnNavigatedFrom(e);
        }

        private void OnPhotoCameraInitialized(object sender, CameraOperationCompletedEventArgs e)
        {
            int width = Convert.ToInt32(_photoCamera.PreviewResolution.Width);
            int height = Convert.ToInt32(_photoCamera.PreviewResolution.Height);

            _luminance = new PhotoCameraLuminanceSource(width, height);
            _reader = new QRCodeReader();

            Dispatcher.BeginInvoke(() =>
            {
                _previewTransform.Rotation = _photoCamera.Orientation;
                _timer.Start();
            });
        }

        private void ScanPreviewBuffer()
        {

        }

        private void DisplayResult(string text)
        {
            if (!_matches.Contains(text))
            {
                _matches.Add(text);
                VerifyQRCode(text, taskID);
            }
        }

        private void VerifyQRCode(string code, int taskID)
        {
            CivilleDataServiceConnector.SetCheckQRCodeQueryParameters(code, taskID);
            CivilleDataServiceConnector.CheckQRCodeQuery.BeginExecute(OnCheckQRCodeQueryComplete, CivilleDataServiceConnector.CheckQRCodeQuery);
        }

        private void OnCheckQRCodeQueryComplete(IAsyncResult result)
        {
            Dispatcher.BeginInvoke(() =>
            {
                DataServiceQuery<QRCode> query = result.AsyncState as DataServiceQuery<QRCode>;
                List<QRCode> codes = query.EndExecute(result).ToList();

                if (codes.Count > 0)
                {
                    codes.First().Status = false;
                    CivilleDataServiceConnector.CivilleContext.UpdateObject(codes.First());
                    CivilleDataServiceConnector.CivilleContext.BeginSaveChanges(OnSaveChangesCompleted, CivilleDataServiceConnector.CivilleContext);
                    MessageBox.Show("Good job!");
                }
                else
                {
                    if (MessageBox.Show("Not a valid Civille QR code. Do you want to scan again?", "Civille", MessageBoxButton.OKCancel) == MessageBoxResult.Cancel)
                    {
                        NavigationService.GoBack();
                    }
                    else
                    {
                        _matches.Clear();
                    }

                }
            });
        }

        private void OnUpdateUserPointsCompleted(IAsyncResult result)
        {
            Dispatcher.BeginInvoke(() =>
            {
                DataServiceQuery<Task> query = result.AsyncState as DataServiceQuery<Task>;
                List<Task> tasks = query.EndExecute(result).ToList();
                CivilleUser user = UserContext.CurrentUser;
                Task currentTask = tasks.First();
                user.Points += currentTask.Points;

                // Carbon tasks
                if (currentTask.TaskTypeID == 1)
                {
                    user.CarbonType++;
                }
                // Diamond tasks
                if (currentTask.TaskTypeID == 2)
                {
                    user.DiamondType++;
                }

                CivilleDataServiceConnector.CivilleContext.UpdateObject(user);
                CivilleDataServiceConnector.GetCurrentLevelRequirementsQueryParameters(user.CurrentLevel);
                CivilleDataServiceConnector.GetCurrentLevelRequirementsQuery.BeginExecute(OnGetCurrentLevelRequirementsCompleted, CivilleDataServiceConnector.GetCurrentLevelRequirementsQuery);

            });
        }

        private void OnGetCurrentLevelRequirementsCompleted(IAsyncResult result)
        {
            Dispatcher.BeginInvoke(() =>
                {
                    DataServiceQuery<Level> query = result.AsyncState as DataServiceQuery<Level>;
                    List<Level> levels = query.EndExecute(result).ToList();
                    CivilleUser user = UserContext.CurrentUser;
                    Level currentLevel = levels.First();

                    if (user.Points - user.LastLevelPoints >= currentLevel.Points
                        && user.CarbonType >= currentLevel.CarbonType && user.DiamondType >= currentLevel.DiamondType)
                    {
                        user.LastLevelPoints = user.Points;
                        user.CurrentLevel++;
                        user.CarbonType = 0;
                        user.DiamondType = 0;
                        levelChanged = true;
                        CivilleDataServiceConnector.CivilleContext.UpdateObject(user);
                    }
                    CivilleDataServiceConnector.CivilleContext.BeginSaveChanges(OnUpdateUserSaveChangesCompleted, CivilleDataServiceConnector.CivilleContext);
                });
        }

        private void OnTaskHistoryUpdateCompleted(IAsyncResult result)
        {
            Dispatcher.BeginInvoke(() =>
               {
                   DataServiceQuery<TaskHistory> query = result.AsyncState as DataServiceQuery<TaskHistory>;
                   List<TaskHistory> taskHistoryList = query.EndExecute(result).ToList();
                   if (taskHistoryList.Count > 0)
                   {
                       currentTaskHistory = taskHistoryList.First();
                       currentTaskHistory.Count++;
                       CivilleDataServiceConnector.CivilleContext.UpdateObject(currentTaskHistory);
                   }
                   else
                   {
                       // the user completed this task for the first time
                       TaskHistory taskHistory = new TaskHistory();
                       taskHistory.UserID = UserContext.CurrentUser.ID;
                       taskHistory.TaskID = taskID;
                       taskHistory.Count = 1;
                       CivilleDataServiceConnector.CivilleContext.AddToTaskHistories(taskHistory);
                       currentTaskHistory = taskHistory;
                   }
                   CivilleDataServiceConnector.CivilleContext.BeginSaveChanges(OnSaveTaskHistoryCompleted, CivilleDataServiceConnector.CivilleContext);
               });
        }

        private void OnSaveTaskHistoryCompleted(IAsyncResult result)
        {
            Dispatcher.BeginInvoke(() =>
               {
                   CivilleEntities context = result.AsyncState as CivilleEntities;
                   context.EndSaveChanges(result);
                   CivilleDataServiceConnector.SetGetRewardsForTaskQueryParameters(taskID);
                   CivilleDataServiceConnector.GetRewardsForTask.BeginExecute(OnGetRewardsForTaskCompleted, CivilleDataServiceConnector.GetRewardsForTask);
               });
        }

        private void OnGetRewardsForTaskCompleted(IAsyncResult result)
        {
            Dispatcher.BeginInvoke(() =>
                {
                    DataServiceQuery<Reward> query = result.AsyncState as DataServiceQuery<Reward>;
                    List<Reward> rewards = query.EndExecute(result).ToList();

                    if (rewards.Count > 0)
                    {
                        // if the user is legit for receiving the reward
                        if (rewards.First().Count == currentTaskHistory.Count)
                        {
                            rewardID = rewards.First().ID;
                            currentTaskHistory.Count = 0;
                        }
                    }
                    CivilleDataServiceConnector.CivilleContext.UpdateObject(currentTaskHistory);
                    CivilleDataServiceConnector.CivilleContext.BeginSaveChanges(OnUpdateTaskHistoryForUserCompleted, CivilleDataServiceConnector.CivilleContext);
                });
        }

        private void OnUpdateTaskHistoryForUserCompleted(IAsyncResult result)
        {
            Dispatcher.BeginInvoke(() =>
            {
                CivilleEntities context = result.AsyncState as CivilleEntities;
                context.EndSaveChanges(result);
                    CivilleDataServiceConnector.SetGetAllBonusesQueryParameters();
                    CivilleDataServiceConnector.GetAllBonusesQuery.BeginExecute(OnGetAllBonusesCompleted, CivilleDataServiceConnector.GetAllBonusesQuery);
            });
        }

        private void OnUpdateRewardForUserCompleted(IAsyncResult result)
        {
            Dispatcher.BeginInvoke(() =>
                {
                    CivilleEntities context = result.AsyncState as CivilleEntities;
                    context.EndSaveChanges(result);
                    rewardID = -1;
                    MessageBox.Show("Yeey! You received a reward!");

                });
        } 

        private void OnGetAllBonusesCompleted(IAsyncResult result)
        {
            Dispatcher.BeginInvoke(() =>
               {
                   DataServiceQuery<Bonu> query = result.AsyncState as DataServiceQuery<Bonu>;
                   List<Bonu> bonuses = query.EndExecute(result).ToList();

                   if (bonuses.Count > 0 && levelChanged)
                   {
                       CivilleUserToBonu newBonusForUser = new CivilleUserToBonu();
                       newBonusForUser.CivilleUserID = UserContext.CurrentUser.ID;
                       // generates random bonus if the user reached a new level
                       Random random = new Random();
                       newBonusForUser.BonusID = bonuses[random.Next(bonuses.Count)].ID;
                       CivilleDataServiceConnector.CivilleContext.AddToCivilleUserToBonus(newBonusForUser);
                   }
                   CivilleDataServiceConnector.CivilleContext.BeginSaveChanges(OnUpdateBonusForUserCompleted, CivilleDataServiceConnector.CivilleContext);
               });
        }

        private void OnUpdateBonusForUserCompleted(IAsyncResult result)
        {
            Dispatcher.BeginInvoke(() =>
               {
                   CivilleEntities context = result.AsyncState as CivilleEntities;
                   context.EndSaveChanges(result);
                   if (levelChanged)
                   {
                       MessageBox.Show("Congratulations! You get a bonus for completing the level!");
                       levelChanged = false;
                   }
                   if (rewardID > 0)
                   {
                       CivilleUserToReward newRewardForUser = new CivilleUserToReward();
                       newRewardForUser.CivilleUserID = UserContext.CurrentUser.ID;
                       newRewardForUser.RewardID = rewardID;

                       CivilleDataServiceConnector.CivilleContext.AddToCivilleUserToRewards(newRewardForUser);
                       CivilleDataServiceConnector.CivilleContext.BeginSaveChanges(OnUpdateRewardForUserCompleted, CivilleDataServiceConnector.CivilleContext);
                   }
               });
        }

        private void OnSaveChangesCompleted(IAsyncResult result)
        {
            Dispatcher.BeginInvoke(() =>
                {
                    CivilleDataServiceConnector.CivilleContext.EndSaveChanges(result);
                    CivilleDataServiceConnector.SetUpdateUserPointsQueryParameters(taskID);
                    CivilleDataServiceConnector.UpdateUserPointsQuery.BeginExecute(OnUpdateUserPointsCompleted, CivilleDataServiceConnector.UpdateUserPointsQuery);
                });
        }

        private void OnUpdateUserSaveChangesCompleted(IAsyncResult result)
        {
            Dispatcher.BeginInvoke(() =>
                {
                    CivilleDataServiceConnector.CivilleContext.EndSaveChanges(result);
                    CivilleDataServiceConnector.SetGetTaskHistoryForUserQueryParameters(UserContext.CurrentUser.ID, taskID);
                    CivilleDataServiceConnector.GetTaskHistoryForUserQuery.BeginExecute(OnTaskHistoryUpdateCompleted, CivilleDataServiceConnector.GetTaskHistoryForUserQuery);
                });
        }
    }
}
